
#include "main.h"												// We're Including theHeader Where Defs And Prototypes
#include <vector>
#include <iostream>

extern S_AppStatus AppStatus;									// We're Using This Struct As A Repository For The Application State (Visible, Focus, ecc)


/*
  class RopeSimulation is derived from class Simulation (see Physics1.h). It simulates a rope with
  point-like particles binded with springs. The springs have inner friction and normal length. One tip of
  the rope is stabilized at a point in space called "Vector3D ropeConnectionPos". This point can be
  moved externally by a method "void setRopeConnectionVel(Vector3D ropeConnectionVel)". RopeSimulation
  creates air friction and a planer surface (or ground) with a normal in +y direction. RopeSimulation
  implements the force applied by this surface. In the code, the surface is refered as "ground".
*/


HairEngine::HairSimulation* hairSimulation = new HairEngine::HairSimulation(80,			//80 links
																			0.05f,		//Each follicle weighs 50 grams
																			10000.0f,	//springConstant in the hair
																			0.05f,		//Normal length of springs in the rope
																			0.2f, 		//Spring inner friction constant
																			HairEngine::Vector3D(0.0f, -9.81f, 0.0f),	//Gravitational acceleration
																			0.02f,		//Air friction constant
																			HairEngine::Vector3D(0.0f, 2.0f, -2.5f)); //Position

HairEngine::HairSimulation* hairSimulation1 = new HairEngine::HairSimulation(80,			//80 links
																			0.05f,		//Each follicle weighs 50 grams
																			10000.0f,	//springConstant in the hair
																			0.05f,		//Normal length of springs in the rope
																			0.2f, 		//Spring inner friction constant
																			HairEngine::Vector3D(0.0f, -9.81f, 0.0f),	//Gravitational acceleration
																			0.02f,		//Air friction constant
																			HairEngine::Vector3D(-0.5f, 2.0f, -2.5f)); //Position

HairEngine::HairSimulation* hairSimulation2 = new HairEngine::HairSimulation(80,			//80 links
																			0.05f,		//Each follicle weighs 50 grams
																			10000.0f,	//springConstant in the hair
																			0.05f,		//Normal length of springs in the rope
																			0.2f, 		//Spring inner friction constant
																			HairEngine::Vector3D(0.0f, -9.81f, 0.0f),	//Gravitational acceleration
																			0.02f,		//Air friction constant
																			HairEngine::Vector3D(0.5f, 2.0f, -2.5f)); //Position

//New Hair simulation object that supports multiple strands
HairEngine::HairSimulationP* hs;

//The 3D location of the stationary ends of the hair strands
std::vector<HairEngine::Vector3D> connections;

// Code
bool InitGL(SDL_Surface *S)										// Any OpenGL Initialization Code Goes Here
{
	glClearColor (0.0f, 0.0f, 0.0f, 0.5f);								// Black Background
	glClearDepth (1.0f);													// Depth Buffer Setup
	glDepthFunc (GL_LEQUAL);											// The Type Of Depth Testing
	glEnable (GL_DEPTH_TEST);											// Enable Depth Testing
	glShadeModel (GL_SMOOTH);											// Select Smooth Shading
	glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);					// Set Perspective Calculations To Most Accurate

	return true;												// Return TRUE (Initialization Successful)
}

bool Initialize(void)											// Any Application & User Initialization Code Goes Here
{
	AppStatus.Visible	= true;								// At The Beginning, Our App Is Visible
	AppStatus.MouseFocus	= true;								// And Have Both Mouse
	AppStatus.KeyboardFocus = true;								// And Input Focus
	
	HairEngine::Vector3D end01(1.0f, 2.0f, -2.5f);
	HairEngine::Vector3D end02(1.5f, 2.0f, -2.5f);
	
	connections.push_back(end01);
	connections.push_back(end02);
	
	hs = new HairEngine::HairSimulationP(80,
										 0.05f,
										 10000.0f,
										 0.05f,
										 0.2f,
										 HairEngine::Vector3D(0.0f, -9.81f, 0.0f),
										 0.02f,
										 connections);
	
	return true;												// Return TRUE (Initialization Successful)
}


void Deinitialize(void)											// Any User Deinitialization Goes Here
{
	hairSimulation->release();
	delete hairSimulation;
	hairSimulation = NULL;
	
	hairSimulation1->release();
	delete hairSimulation1;
	hairSimulation1 = NULL;
	
	hairSimulation2->release();
	delete hairSimulation2;
	hairSimulation2 = NULL;
	
	hs->release();
	delete hs;
	hs = NULL;
	
	return;														// We Have Nothing To Deinit Now
}

void Update(Uint32 milliseconds, Uint8 *Keys)					// Perform Motion Updates Here
{
	if(Keys)													// If We're Sent A Key Event With The Update
	{
		if(Keys[SDLK_ESCAPE])									// And If The Key Pressed Was ESC
		{
			TerminateApplication();								// Terminate The Application
		}

		if(Keys[SDLK_F1])										// If The Key Pressed Was F1
		{
			ToggleFullscreen();									// Use SDL Function To Toggle Fullscreen Mode (But Not In Windows :) )
		}
		
		/*
		Vector3D ropeConnectionVel;						// Create A Temporary Vector3D
		
		if(Keys[SDLK_UP])										// If The Key Pressed Was Up Arrow
		{
			ropeConnectionVel.z -= 3.0f;					// Add Velocity In +Z Direction
		}

		if(Keys[SDLK_DOWN])										// If The Key Pressed Was Down Arrow
		{
			ropeConnectionVel.z += 3.0f;					// Add Velocity In -Z Direction
		}

		if(Keys[SDLK_LEFT])										// If The Key Pressed Was Left Arrow
		{
			ropeConnectionVel.x -= 3.0f;						// Add Velocity In -X Direction
		}

		if(Keys[SDLK_RIGHT])										// If The Key Pressed Was Right Arrow
		{
			ropeConnectionVel.x += 3.0f;						// Add Velocity In +X Direction
		}

		if(Keys[SDLK_HOME])										// If The Key Pressed Was Right Arrow
		{
			ropeConnectionVel.y += 3.0f;						// Add Velocity In +Y Direction
		}

		if(Keys[SDLK_END])										// If The Key Pressed Was Right Arrow
		{
			ropeConnectionVel.y -= 3.0f;						// Add Velocity In -Y Direction
		}
		ropeSimulation->setRopeConnectionVel(ropeConnectionVel);		// Set The Obtained ropeConnectionVel In The Simulation
		*/
		
		float dt = milliseconds / 1000.0f;										// Let's Convert Milliseconds To Seconds

		float maxPossible_dt = 0.002f;											// Maximum Possible dt Is 0.002 Seconds
																				// This Is Needed To Prevent Pass Over Of A Non-Precise dt Value

	  	int numOfIterations = (int)(dt / maxPossible_dt) + 1;					// Calculate Number Of Iterations To Be Made At This Update Depending On maxPossible_dt And dt
		if (numOfIterations != 0)												// Avoid Division By Zero
			dt = dt / numOfIterations;											// dt Should Be Updated According To numOfIterations

		for (int a = 0; a < numOfIterations; ++a)								// We Need To Iterate Simulations "numOfIterations" Times
		{
			hairSimulation->operate(dt);
			hairSimulation1->operate(dt);
			hairSimulation2->operate(dt);
			hs->operate(dt);
		}
	
	}

	return;														// We Always Make Functions Return
}

void Draw(void)													// Our Drawing Code
{
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity ();														// Reset The Modelview Matrix

	// Position Camera 40 Meters Up In Z-Direction.
	// Set The Up Vector In Y-Direction So That +X Directs To Right And +Y Directs To Up On The Window.
	gluLookAt(0, 0, 4, 0, 0, 0, 0, 1, 0);

	glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);					// Clear Screen And Depth Buffer
	
	//Start drawing the hair strand
	glColor3ub(255, 0, 0);						//Set colour to red
	for(int index = 0; index < hairSimulation->numOfLinks - 1; index++)
	{
		HairEngine::Link* link1 = hairSimulation->getLink(index);
		HairEngine::Vector3D* pos1 = &link1->pos;
		
		HairEngine::Link* link2 = hairSimulation->getLink(index+1);
		HairEngine::Vector3D* pos2 = &link2->pos;
		
		glLineWidth(4);
		glBegin(GL_LINES);
			glVertex3f(pos1->x, pos1->y, pos1->z);
			glVertex3f(pos2->x, pos2->y, pos2->z);
		glEnd();
	}
	
	for(int index = 0; index < hairSimulation1->numOfLinks - 1; index++)
	{
		HairEngine::Link* link1 = hairSimulation1->getLink(index);
		HairEngine::Vector3D* pos1 = &link1->pos;
		
		HairEngine::Link* link2 = hairSimulation1->getLink(index+1);
		HairEngine::Vector3D* pos2 = &link2->pos;
		
		glLineWidth(4);
		glBegin(GL_LINES);
			glVertex3f(pos1->x, pos1->y, pos1->z);
			glVertex3f(pos2->x, pos2->y, pos2->z);
		glEnd();
	}
	
	for(int index = 0; index < hairSimulation2->numOfLinks - 1; index++)
	{
		HairEngine::Link* link1 = hairSimulation2->getLink(index);
		HairEngine::Vector3D* pos1 = &link1->pos;
		
		HairEngine::Link* link2 = hairSimulation2->getLink(index+1);
		HairEngine::Vector3D* pos2 = &link2->pos;
		
		glLineWidth(4);
		glBegin(GL_LINES);
			glVertex3f(pos1->x, pos1->y, pos1->z);
			glVertex3f(pos2->x, pos2->y, pos2->z);
		glEnd();
	}

	
	glColor3f(0.0f, 1.0f, 0.0f);
	
	for(int count = 0; count < hs->numStrands; count++)
	{
		HairEngine::Strand *strand = hs->getStrand(count);
		
		for(int index = 0; index < strand->numOfLinks-1; index++)
		{
			HairEngine::Link* link1 = strand->getLink(index);
			HairEngine::Vector3D* pos1 = &link1->pos;
			
			HairEngine::Link* link2 = strand->getLink(index+1);
			HairEngine::Vector3D* pos2 = &link2->pos;
			
			glLineWidth(4);
			glBegin(GL_LINES);
				glVertex3f(pos1->x, pos1->y, pos1->z);
				glVertex3f(pos2->x, pos2->y, pos2->z);
			glEnd();
		}
	}
	
	//Draw line representing the skin
	
	glColor3ub(255, 200,190);		//Change color to pink
	glLineWidth(3);
	glBegin(GL_LINES);
		glVertex3f(-2.0f, 2.0f, -2.5f);
		glVertex3f( 2.0f, 2.0f, -2.5f);
	glEnd();
	
	glFlush ();													// Flush The GL Rendering Pipeline

	return;														// We're Always Making Functions Return
}

